真實世界的卷積神經網路開發
林嶔 (Lin, Chin)
– 事實上我們從事後的角度來說,深度學習是一個需要數據量才能體現出的強大算法,假設我們一直沒有足夠的數據量,那深度學習將永無抬頭之日!
– 下面這張圖是每一年的冠軍演算法,我們可以看到在2012年以前,這項比賽大多是由SVM、隨機森林等方法獲得冠軍,但自2012年以來卷積神經網路就席捲了ILSVRC之後所有的冠軍。
– 除此之外,由於ImageNet上的比賽是對圖像做1000類別的分類,但我們並不清楚是哪1000個類別,model裡面的chinese synset.txt描述著第幾個類別是什麼的資訊。
library(OpenImageR)
img = readImage('image/test.jpg')
resized_img = resizeImage(img, 224, 224, method = 'bilinear')
imageShow(resized_img)
norm_img = resized_img
norm_img = norm_img * 255
norm_img = norm_img - 128
dim(norm_img) = c(224, 224, 3, 1)
library(mxnet)
inception_model = mx.model.load("model/Inception-BN", 126)
pred_prob = predict(inception_model, norm_img)
which.max(pred_prob)
## [1] 3
synsets <- readLines('model/chinese synset.txt', encoding = 'UTF-8')
pred_prob <- as.numeric(pred_prob)
names(pred_prob) <- synsets
pred_prob <- sort(pred_prob, decreasing = TRUE)
pred_prob <- formatC(pred_prob, 4, format = 'f')
head(pred_prob, 5)
## n01484850 大白鯊 n03045698 斗篷
## "0.8162" "0.0591"
## n03916031 香水(瓶) n02071294 殺人鯨,逆戟鯨,虎鯨
## "0.0125" "0.0091"
## n03388043 噴泉
## "0.0080"
– 其中global.R描述了模型及標籤檔案的位置,以及定義了前處理的函數
– ui.R負責定義使用者介面
– server.R中定義了程式對於使用者動作的相對應反應
– 我們有個想法,能不能使用這些經典模型的參數當作初始權重,並在這個基礎上訓練網路完成我們的任務目標。這個想法稱作轉移特徵學習(Transfer learning),而這個想法是基於人類通常具有舉一反三的能力,舉例來說一個剛入學的醫學系學生他們僅有接受過高中程度的基礎訓練,並未接受過任何醫學專業領域的訓練,但他們的學習因為是基於高中的基礎之上,因此即使醫學專業相當艱深也能相當快的學會。
– 一般來說,有使用轉移特徵學習的概念先將網路在大資料上學習(主題可以與目標任務幾乎無關),而後再到目標任務中訓練,其準確度會更好。
– 舉例來說,我們可以定義我們要整個Inception-BN除了最後一個全連接層外的所有結構,只把最後一層的FC從分1000類轉變成分2類:
library(mxnet)
inception_model = mx.model.load("model/Inception-BN", 126)
all_layers = inception_model$symbol$get.internals()
flatten_pos = which(all_layers$outputs == 'flatten_output')
flatten_output = all_layers$get.output(flatten_pos)
fc1 <- mx.symbol.FullyConnected(data = flatten_output, num_hidden = 2, name = 'fc1')
softmax <- mx.symbol.SoftmaxOutput(data = fc1, name = 'softmax')
Train_img = array(0, dim = c(224, 224, 3, 200))
Train.y = array(0, dim = c(2, 200))
for (i in 1:100) {
# Cat
img = readImage(paste0('Dogs vs. Cats/cat.', i, '.jpg'))
resized_img = resizeImage(img, 224, 224, method = 'bilinear')
Train_img[,,,2*i-1] = resized_img
Train.y[1,2*i-1] = 1
# Dog
img = readImage(paste0('Dogs vs. Cats/dog.', i, '.jpg'))
resized_img = resizeImage(img, 224, 224, method = 'bilinear')
Train_img[,,,2*i] = resized_img
Train.y[2,2*i] = 1
}
Train_img = Train_img * 255 - 128
– 接著,我們在開始訓練之前需要取得模型權重參數,我們可以將最後一層以外的部分填入Inception-BN的參數,並以這為基礎開始訓練任務:
mx.set.seed(0)
new_arg = mxnet:::mx.model.init.params(symbol = softmax,
input.shape = list(data = c(224, 224, 3, 20)),
output.shape = NULL,
initializer = mxnet:::mx.init.uniform(0.01),
ctx = mx.cpu())
for (i in 1:length(new_arg$arg.params)) {
pos = which(names(inception_model$arg.params) == names(new_arg$arg.params)[i])
if (all.equal(dim(inception_model$arg.params[[pos]]), dim(new_arg$arg.params[[i]])) == TRUE) {
new_arg$arg.params[[i]] = inception_model$arg.params[[pos]]
}
}
for (i in 1:length(new_arg$aux.params)) {
pos = which(names(inception_model$aux.params) == names(new_arg$aux.params)[i])
if (all.equal(dim(inception_model$aux.params[[pos]]), dim(new_arg$aux.params[[i]])) == TRUE) {
new_arg$aux.params[[i]] = inception_model$aux.params[[pos]]
}
}
my.eval.metric.mlogloss <- mx.metric.custom(
name = "m-logloss",
function(real, pred) {
real1 = as.numeric(as.array(real))
pred1 = as.numeric(as.array(pred))
pred1[pred1 <= 1e-6] = 1e-6
pred1[pred1 >= 1 - 1e-6] = 1 - 1e-6
return(-mean(real1 * log(pred1), na.rm = TRUE))
}
)
FIXED_NAMES = names(new_arg$arg.params)
FIXED_NAMES = FIXED_NAMES[1:276]
FIXED_NAMES = c(FIXED_NAMES, names(new_arg$aux.params))
mx.set.seed(0)
my_model = mx.model.FeedForward.create(symbol = softmax,
X = Train_img, y = Train.y,
optimizer = "sgd", learning.rate = 0.001, momentum = 0.9,
array.batch.size = 10, num.round = 20,
arg.params = new_arg$arg.params, aux.params = new_arg$aux.params,
fixed.param = FIXED_NAMES,
ctx = mx.cpu(),
eval.metric = my.eval.metric.mlogloss)
my_model$arg.params = append(my_model$arg.params, new_arg$arg.params[1:276])
my_model$aux.params = new_arg$aux.params
img = readImage('Dogs vs. Cats/test_cat.3.jpg')
resized_img = resizeImage(img, 224, 224, method = 'bilinear')
imageShow(resized_img)
norm_img = resized_img
norm_img = norm_img * 255
norm_img = norm_img - 128
dim(norm_img) = c(224, 224, 3, 1)
pred_prob = predict(my_model, norm_img)
pred_prob
## [,1]
## [1,] 0.993675292
## [2,] 0.006324741
img = readImage('Dogs vs. Cats/test_dog.3.jpg')
resized_img = resizeImage(img, 224, 224, method = 'bilinear')
imageShow(resized_img)
norm_img = resized_img
norm_img = norm_img * 255
norm_img = norm_img - 128
dim(norm_img) = c(224, 224, 3, 1)
pred_prob = predict(my_model, norm_img)
pred_prob
## [,1]
## [1,] 0.4262857
## [2,] 0.5737143
– 如果你想把自己訓練的模型放到剛剛的App內,還要記得改變chinese synset.txt檔案喔!
– 另外,深度學習的潛力可不僅僅只有圖像辨識任務,其他包含物件識別、物件分割、圖像生成,甚至是語言模型,都是可以做出來的,這也值得有興趣的人再進一步學習!